﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using AzukiMap.Map;
using Geotools.Geometries;
using AzukiMap.Tools;
using AzukiMap.Tools.Logger;
using System.Windows.Media.Imaging;

namespace AzukiMap.Renderer
{
    public class TileRenderer
    {
        MapCanvas _mapCanvas;
        GeometryUtil _geoUtil;

        public TileRenderer(MapCanvas mapCanvas)
        {
            _mapCanvas = mapCanvas;
            _geoUtil = new GeometryUtil();
        }

        public void RenderTile(TileData tile)
        {
            Image tileImg = CreateTileImage(tile);
            SetCanvasData(tile);
            TransformTile(tileImg, tile.OrgExtent, tile.OrgTileWidth, tile.OrgTileHeight);
            SetPosition(tileImg, tile.OrgExtent);

            _mapCanvas.Children.Add(tileImg);
        }

        Image CreateTileImage(TileData tile) {
            Image tileImg = new Image();
            ImageSource imgsrc = new BitmapImage(tile.Uri);
            tileImg.ImageFailed += new EventHandler<ExceptionRoutedEventArgs>(OnTileImg_ImageFailed);
            tileImg.Source = imgsrc;

            return tileImg;
        }

        void SetCanvasData(TileData tile)
        {
            tile.Dpi = AzukiMapSettings.DPI;
            tile.Srid = _mapCanvas.Srid;
            tile.Unit = _mapCanvas.Unit;
            tile.Extent = tile.OrgExtent;
        }

        //void TransformTile(TileData tile)
        void TransformTile(Image tileImg, GTPolygon orgExtent, double orgTileWidth, double orgTileHeight)
        {
            tileImg.Width = _geoUtil.GetExtentPolygonWidth(orgExtent) / _mapCanvas.ScreenScale;
            tileImg.Height = _geoUtil.GetExtentPolygonHeight(orgExtent) / _mapCanvas.ScreenScale;
            tileImg.RenderTransform = GetImageTransform(tileImg, orgExtent, orgTileWidth, orgTileHeight);
        }

        void SetPosition(Image tileImg, GTPolygon orgExtent)
        {
            // TODO: projection change
            GTCoordinate tlPoint = _geoUtil.GetExtentPoint(orgExtent, ExtentOrder.TOP_LEFT);
            GTPoint pixPoint = _mapCanvas.GetPixPointFromGeo(tlPoint.X, tlPoint.Y);
            tileImg.SetValue(Canvas.LeftProperty, pixPoint.X);
            tileImg.SetValue(Canvas.TopProperty, pixPoint.Y);
            Logger.All("TileRenderer.SetPosition(): " + pixPoint.X + " " + pixPoint.Y);
        }

        TransformGroup GetImageTransform(Image tileImg, GTPolygon orgExtent, double orgTileWidth, double orgTileHeight)
        {
            TransformGroup transGroup = new TransformGroup();
            TranslateTransform moveTransform = new TranslateTransform();
            ScaleTransform scaleTransform = new ScaleTransform();

            double geoWidth = _geoUtil.GetExtentPolygonWidth(orgExtent);
            double geoHeight = _geoUtil.GetExtentPolygonHeight(orgExtent);
            double imgOrgWidth = orgTileWidth;
            double imgOrgHeight = orgTileHeight;

            double geoAspectRatio = geoWidth / geoHeight;
            double imgAspectRatio = imgOrgWidth / imgOrgHeight;

            double scaleX = geoAspectRatio / imgAspectRatio;
            double moveX = GetImageWidth(orgExtent) * (( scaleX - 1 ) / 2) * -1;

            scaleTransform.ScaleX = scaleX;
            moveTransform.X = moveX;

            transGroup.Children.Add(scaleTransform);
            transGroup.Children.Add(moveTransform);

            return transGroup;
        }

        double GetImageWidth(GTPolygon orgExtent)
        {
            double extentWidth = _geoUtil.GetExtentPolygonWidth(orgExtent);
            return extentWidth / _mapCanvas.ScreenScale;
        }

        void SetNoImage(Image tileImg)
        {
            tileImg.Source = new BitmapImage(new Uri(AzukiMapSettings.NO_IMAGE_TILE));
            tileImg.Stretch = Stretch.UniformToFill;
        }

        void OnTileImg_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {
            SetNoImage(((Image)sender));
        }


    }
}
